package com.sa.gateway.filter;

import com.sa.gateway.entry.LogEntry;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;

/**
 * @author Architecture Station
 * @version 1.0
 */
//@Component
@Order(0)
@Slf4j
@RefreshScope
public class LoggingGlobalFilter implements GlobalFilter {

    private final Random random = new Random();

    @Value("${log.sampling.rate:0.1}")
    private double samplingRate;

    @Value("#{'${sensitive-parameters}'.split(',')}")
    private Set<String> sensitiveParameters;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if(shouldLog()){
            ServerHttpRequest request = exchange.getRequest();
            long startTime = System.currentTimeMillis();
            return chain.filter(exchange).doFinally(signal -> {
                ServerHttpResponse response = exchange.getResponse();
                long endTime = System.currentTimeMillis();
                // 初始化LogEntry对象
                LogEntry logEntry = new LogEntry();
                logEntry.setTimestamp(Instant.now().toString());
                logEntry.setMethod(request.getMethod().name());
                logEntry.setUri(request.getURI().toString());
                logEntry.setStatus(response.getStatusCode().value());
                logEntry.setDuration(endTime - startTime);
                logEntry.setClientIp(request.getRemoteAddress().getAddress().getHostAddress());
                logEntry.setClientPort(request.getRemoteAddress().getPort());
                logEntry.setRequestParams(filterParams(request.getQueryParams().toSingleValueMap()));
                log.info("LogEntry:{}",logEntry);
                sendLogToLogStash(logEntry);
            });
        }
        return chain.filter(exchange);
    }

    private void sendLogToLogStash(LogEntry logEntry) {
        // todo
    }

    private Map<String,String> filterParams(Map<String,String> params){
        Map<String,String> filteredParams = new HashMap<String, String>();
        params.forEach((key,value)->{
            if(!sensitiveParameters.contains(key)){
                filteredParams.put(key,value);
            }
        });
        return filteredParams;
    }

    private boolean shouldLog(){
        return random.nextDouble() < samplingRate;
    }

}
























